import os.path
import shutil
import tkinter
from multiprocessing import Queue
from tkinter import ttk, filedialog, messagebox

from app.file_scanner import FileScanner
from app.list_store import ListStore
from app.ui.progress_dialog import ProgressDialog
from app.ui.waiting_dialog import WaitingDialog
from app.xls2xlsx_converter import Xls2XlsxConverter


class MainWindow:

    def __init__(self):
        self.window = tkinter.Tk()
        self.btn_open_source_file_dialog = None
        self.btn_open_target_file_dialog = None
        self.check_btn_include_sub_folder = None
        self.check_btn_include_sub_folder_var: tkinter.BooleanVar = tkinter.BooleanVar(value=True)
        self.check_btn_copy_other_files = None
        self.check_btn_copy_other_files_var: tkinter.BooleanVar = tkinter.BooleanVar(value=True)
        self.btn_start: tkinter.Button = None
        self.txt_target_folder = None
        self.txt_target_folder_var: tkinter.StringVar = tkinter.StringVar()
        self.txt_source_folder = None
        self.txt_source_folder_var: tkinter.StringVar = tkinter.StringVar()
        self.list_source_file: tkinter.Listbox = None
        self.list_source_file_var: ListStore = ListStore()
        self.converter_progressbar = None
        self.converter_progressbar_var = tkinter.IntVar()

    def init_window(self):
        self.window.title("xls转xlsx小工具 v1.0 by huangyi")
        # 不可改变大小
        self.window.resizable(False, False)

        icon_path = os.path.realpath("resources/converter.ico")
        self.window.iconbitmap(icon_path)

    def show(self):
        self.init_window()
        # 目录选择面板
        self.init_select_folder_layer(self.window)
        # 文件列表
        self.init_file_list(self.window)
        # 进度条
        self.init_progressbar(self.window)
        # 转换按钮
        self.init_btn_layer(self.window)
        # 开始窗体循环
        self.window.mainloop()

    def on_btn_open_target_file_dialog_click(self):
        folder_path = filedialog.askdirectory(parent=self.window)
        if folder_path:
            # 获取真实目录地址
            folder_path = os.path.abspath(folder_path)
            self.txt_target_folder_var.set(folder_path)

    def on_btn_open_source_file_dialog_click(self):
        folder_path = filedialog.askdirectory(parent=self.window)
        if folder_path:
            # 获取真实目录地址
            folder_path = os.path.abspath(folder_path)
            # 记录源目录
            self.txt_source_folder_var.set(folder_path)
            # 记录存储目录
            source_path = os.path.abspath(os.path.dirname(folder_path))
            source_folder_name = os.path.basename(folder_path)
            target_folder_name = f"{source_folder_name}_xlsx"
            self.txt_target_folder_var.set(os.path.join(source_path, target_folder_name))
            dialog = WaitingDialog(self.window)
            dialog.show(call_back=lambda: self.find_xls_files(folder_path, self.check_btn_include_sub_folder_var.get()))

    def find_xls_files(self, source_root_path, scan_deep: bool):
        scanner = FileScanner()
        filter_suffix = ".xls"
        if self.check_btn_copy_other_files_var.get():
            filter_suffix = None
        scanner.scan(source_root_path, scan_deep=scan_deep, filter_suffix=filter_suffix,
                     call_back=lambda file_path: self.list_source_file_var.append(file_path,
                                                                                  root_path=source_root_path))

    def init_file_list(self, window):
        frame = tkinter.Frame(window)
        frame.pack(fill=tkinter.X, padx=10, pady=10)
        y_scroll_bar = tkinter.Scrollbar(frame)
        y_scroll_bar.pack(side=tkinter.RIGHT, fill=tkinter.Y)
        x_scroll_bar = tkinter.Scrollbar(frame, orient=tkinter.HORIZONTAL)
        x_scroll_bar.pack(side=tkinter.BOTTOM, fill=tkinter.X)
        self.list_source_file = tkinter.Listbox(frame, yscrollcommand=y_scroll_bar.set, xscrollcommand=x_scroll_bar.set,
                                                selectmode=tkinter.SINGLE, listvariable=self.list_source_file_var.var)
        self.list_source_file.pack(fill=tkinter.X)
        y_scroll_bar.config(command=self.list_source_file.yview)
        x_scroll_bar.config(command=self.list_source_file.xview)

    def init_select_folder_layer(self, window):
        frame = tkinter.Frame(window)
        frame.pack(fill=tkinter.X, padx=10, pady=10)
        # 源文件目录
        tkinter.Label(frame, text="源文件目录").grid(row=0, column=0, sticky="w")

        self.txt_source_folder = tkinter.Entry(frame, textvariable=self.txt_source_folder_var, width=50)
        self.txt_source_folder.grid(row=0, column=1, columnspan=3)

        self.btn_open_source_file_dialog = tkinter.Button(frame, text="选择目录",
                                                          command=self.on_btn_open_source_file_dialog_click)
        self.btn_open_source_file_dialog.grid(row=0, column=4, padx=10)

        self.check_btn_include_sub_folder = tkinter.Checkbutton(frame, text="包含子目录",
                                                                variable=self.check_btn_include_sub_folder_var)
        self.check_btn_include_sub_folder.grid(row=0, column=5,  sticky="w", padx=10)

        # 转换后存储目录
        tkinter.Label(frame, text="转换后存储目录").grid(row=1, column=0, sticky="w")

        self.txt_target_folder = tkinter.Entry(frame, textvariable=self.txt_target_folder_var, width=50)
        self.txt_target_folder.grid(row=1, column=1, columnspan=3)

        self.btn_open_target_file_dialog = tkinter.Button(frame, text="选择目录",
                                                          command=self.on_btn_open_target_file_dialog_click)
        self.btn_open_target_file_dialog.grid(row=1, column=4, sticky="w", padx=10)
        self.check_btn_copy_other_files = tkinter.Checkbutton(frame, text="同步拷贝除xls外其他文件到存储目录",
                                                              command=self.on_check_btn_copy_other_files_change,
                                                              variable=self.check_btn_copy_other_files_var)
        self.check_btn_copy_other_files.grid(row=1, column=5, padx=10)

    def on_check_btn_copy_other_files_change(self):
        folder_path = self.txt_source_folder_var.get()
        self.list_source_file_var.clear()
        dialog = WaitingDialog(self.window)
        dialog.show(call_back=lambda: self.find_xls_files(folder_path, self.check_btn_include_sub_folder_var.get()))

    def init_progressbar(self, window):
        frame = tkinter.Frame(window)
        frame.pack(fill=tkinter.X, padx=10, pady=10)
        self.converter_progressbar = ttk.Progressbar(frame, maximum=100, length=800, mode="determinate",
                                                     orient=tkinter.HORIZONTAL, variable=self.converter_progressbar_var)
        self.converter_progressbar.pack(fill=tkinter.X)

    def init_btn_layer(self, window):
        frame = tkinter.Frame(window)
        frame.pack(pady=10)
        self.btn_start = tkinter.Button(frame, text="开始转换", command=lambda: self.on_btn_start_click())
        self.btn_start.pack()

    def on_btn_start_click(self):
        messagebox.showwarning("提示", "转换工具需要调用office/wps, 请先保存正在编辑的文件，以免造成损失")
        self.btn_start.config(state=tkinter.DISABLED, text="转换中")
        dlg = ProgressDialog(self.window)
        dlg.show(
            call_back=lambda queue: self.on_start_convert_progress_call_back(
                xls_file_path_list=self.list_source_file_var,
                target_root_path=self.txt_target_folder_var.get(),
                queue=queue,
                is_copy_other_files=self.check_btn_copy_other_files_var.get(),
                btn_start=self.btn_start))

    def on_start_convert_progress_call_back(self, xls_file_path_list: ListStore, target_root_path: str,
                                            btn_start: tkinter.Button, queue: Queue, is_copy_other_files: bool):
        """
        开始转换xls（在等待对话框里）
        :param queue:
        :param btn_start:
        :param target_root_path:
        :param xls_file_path_list:
        :param is_copy_other_files:
        :return:
        """
        converter = Xls2XlsxConverter()
        try:
            if xls_file_path_list.len() == 0:
                messagebox.showinfo("提示", f"没有可转换的文件，请先选择目录")
                return
            if not os.path.exists(target_root_path):
                os.makedirs(target_root_path)

            total = xls_file_path_list.len()
            for index, item in enumerate(xls_file_path_list.data):
                progress = int((index + 1) / total * 100)
                # 往队列丢进度更新
                queue.put(progress)
                if item.file_name.endswith(".xls"):
                    source_file_path = item.file_path
                    source_file_path_without_root_path = source_file_path[len(item.source_root_path) + 1:]
                    target_file_path = os.path.join(target_root_path, source_file_path_without_root_path)
                    target_file_folder = os.path.dirname(target_file_path)
                    if not os.path.exists(target_file_folder):
                        os.makedirs(target_file_folder)
                    converter.xls_to_xlsx(source_file_path, target_file_path)
                else:
                    if is_copy_other_files:
                        # 复制其他文件
                        source_file_path = item.file_path
                        source_file_path_without_root_path = source_file_path[len(item.source_root_path) + 1:]
                        target_file_path = os.path.join(target_root_path, source_file_path_without_root_path)
                        target_file_folder = os.path.dirname(target_file_path)
                        if not os.path.exists(target_file_folder):
                            os.makedirs(target_file_folder)
                        shutil.copy(source_file_path, target_file_path)
            # 转换完成工作
            xls_file_path_list.clear()  # 清理列表
            if messagebox.askokcancel("转换完成", f"文档全部转换完成, 是否打开转换后文件夹"):
                os.startfile(target_root_path)
        except Exception as e:
            messagebox.showerror("转换出错", f"转换出错，请联系开发\n\r{e}")
        finally:
            # 关闭应用
            converter.close()
            btn_start.config(state=tkinter.NORMAL, text="开始转换")
